package com.ehsunbehravesh.mypasswords.gui;

import com.ehsunbehravesh.mypasswords.Domain;
import com.ehsunbehravesh.mypasswords.Logger;
import com.ehsunbehravesh.mypasswords.Utils;
import com.ehsunbehravesh.mypasswords.entity.PasswordEntry;
import com.ehsunbehravesh.mypasswords.entity.PasswordTag;
import com.ehsunbehravesh.mypasswords.resource.ResourceLoader;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class SearchDialog extends javax.swing.JDialog {
  private String countCaption = "Count";

  public SearchDialog(java.awt.Frame parent, boolean modal) {
    super(parent, modal);
    initComponents();
    myInitComponent();
    Utils.setCenterOfParent((JFrame) getParent(), this);
  }

  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    pnlMain = new javax.swing.JPanel();
    lblTitle = new javax.swing.JLabel();
    txtTitle = new javax.swing.JTextField();
    lblTag = new javax.swing.JLabel();
    txtTags = new javax.swing.JTextField();
    scpResults = new javax.swing.JScrollPane();
    tblResult = new javax.swing.JTable();
    btnSearch = new javax.swing.JButton();
    lblCount = new javax.swing.JLabel();

    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
    setTitle("Search");
    setResizable(false);

    pnlMain.setBackground(new java.awt.Color(255, 255, 255));

    lblTitle.setText("Title:");

    txtTitle.addKeyListener(new java.awt.event.KeyAdapter() {
      public void keyReleased(java.awt.event.KeyEvent evt) {
        txtTitleKeyReleased(evt);
      }
    });

    lblTag.setText("Tag:");

    txtTags.addKeyListener(new java.awt.event.KeyAdapter() {
      public void keyPressed(java.awt.event.KeyEvent evt) {
        txtTagsKeyPressed(evt);
      }
      public void keyReleased(java.awt.event.KeyEvent evt) {
        txtTagsKeyReleased(evt);
      }
    });

    scpResults.setBorder(javax.swing.BorderFactory.createEtchedBorder());

    tblResult.setAutoCreateRowSorter(true);
    tblResult.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
    tblResult.setModel(new javax.swing.table.DefaultTableModel(
      new Object [][] {

      },
      new String [] {
        "Title", "Username", "URL", "ID"
      }
    ) {
      Class[] types = new Class [] {
        java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class
      };
      boolean[] canEdit = new boolean [] {
        false, false, false, false
      };

      public Class getColumnClass(int columnIndex) {
        return types [columnIndex];
      }

      public boolean isCellEditable(int rowIndex, int columnIndex) {
        return canEdit [columnIndex];
      }
    });
    tblResult.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent evt) {
        tblResultMouseClicked(evt);
      }
    });
    scpResults.setViewportView(tblResult);

    btnSearch.setText("Search");
    btnSearch.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        btnSearchActionPerformed(evt);
      }
    });
    btnSearch.addKeyListener(new java.awt.event.KeyAdapter() {
      public void keyPressed(java.awt.event.KeyEvent evt) {
        btnSearchKeyPressed(evt);
      }
    });

    javax.swing.GroupLayout pnlMainLayout = new javax.swing.GroupLayout(pnlMain);
    pnlMain.setLayout(pnlMainLayout);
    pnlMainLayout.setHorizontalGroup(
      pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(pnlMainLayout.createSequentialGroup()
        .addGap(20, 20, 20)
        .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(pnlMainLayout.createSequentialGroup()
            .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(lblTitle)
              .addComponent(lblTag))
            .addGap(36, 36, 36)
            .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
              .addComponent(txtTags)
              .addComponent(txtTitle, javax.swing.GroupLayout.DEFAULT_SIZE, 379, Short.MAX_VALUE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 30, Short.MAX_VALUE))
          .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
            .addComponent(scpResults, javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, pnlMainLayout.createSequentialGroup()
              .addComponent(lblCount, javax.swing.GroupLayout.PREFERRED_SIZE, 374, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addGap(24, 24, 24)
              .addComponent(btnSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE))))
        .addGap(34, 34, 34))
    );
    pnlMainLayout.setVerticalGroup(
      pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(pnlMainLayout.createSequentialGroup()
        .addGap(17, 17, 17)
        .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
          .addComponent(lblTitle)
          .addComponent(txtTitle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addGap(18, 18, 18)
        .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
          .addComponent(lblTag)
          .addComponent(txtTags, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addGap(18, 18, 18)
        .addGroup(pnlMainLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
          .addGroup(pnlMainLayout.createSequentialGroup()
            .addComponent(btnSearch)
            .addGap(26, 26, 26))
          .addGroup(pnlMainLayout.createSequentialGroup()
            .addComponent(lblCount, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addGap(18, 18, 18)))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(scpResults, javax.swing.GroupLayout.PREFERRED_SIZE, 299, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addContainerGap(20, Short.MAX_VALUE))
    );

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(pnlMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(pnlMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

    private void txtTitleKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtTitleKeyReleased
      int key = evt.getKeyCode();
      if (key == 10) {
        doSearch();
      } else if (key == 27) {
        closeDialog();
      }
}//GEN-LAST:event_txtTitleKeyReleased

    private void txtTagsKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtTagsKeyPressed
      int key = evt.getKeyCode();
      if (key == 44) {
        txtTags.setSelectionStart(txtTags.getText().length());
        txtTags.setSelectionEnd(txtTags.getText().length());
      }
}//GEN-LAST:event_txtTagsKeyPressed

    private void txtTagsKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txtTagsKeyReleased
      int key = evt.getKeyCode();

      if (key >= 33 && key <= 40) {
        return;
      } else if (key == 8) {
        return;
      } else if (key == 10) {
        if (txtTags.getSelectedText() != null) {
          txtTags.setSelectionStart(txtTags.getText().length());
          txtTags.setSelectionEnd(txtTags.getText().length());
        } else {
          doSearch();
        }
      } else if (key == 27) {
        closeDialog();
      }

      String lastTag = "";
      StringTokenizer tokenTags = new StringTokenizer(txtTags.getText(), ",");
      while (tokenTags.hasMoreTokens()) {
        lastTag = tokenTags.nextToken().trim();
      }

      if (lastTag.length() > 1) {
        String candidTag = searchInTags(lastTag);
        if (candidTag.length() > 0) {
          String restOfCandidTag = Utils.getRestOfStrings(lastTag, candidTag);
          txtTags.setText(txtTags.getText() + restOfCandidTag);
          txtTags.setSelectionStart(txtTags.getText().lastIndexOf(restOfCandidTag));
          txtTags.setSelectionEnd(txtTags.getText().length());
        }
      }
}//GEN-LAST:event_txtTagsKeyReleased

    private void tblResultMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tblResultMouseClicked
      int row = tblResult.getSelectedRow();
      if (SwingUtilities.isLeftMouseButton(evt)) {
        if (evt.getClickCount() == 2) {
          if (row >= 0) {
            showPassword();
          }
        }
      } else if (SwingUtilities.isRightMouseButton(evt)) {
        Point point = evt.getPoint();
        int rowNumber = tblResult.rowAtPoint(point);
        ListSelectionModel model = tblResult.getSelectionModel();
        model.setSelectionInterval(rowNumber, rowNumber);
        mnuResults.show(tblResult, point.x, point.y);
      }
}//GEN-LAST:event_tblResultMouseClicked

    private void btnSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSearchActionPerformed
      doSearch();
}//GEN-LAST:event_btnSearchActionPerformed

    private void btnSearchKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_btnSearchKeyPressed
      int key = evt.getKeyCode();
      if (key == 10) {
        doSearch();
      } else if (key == 27) {
        closeDialog();
      }
}//GEN-LAST:event_btnSearchKeyPressed
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton btnSearch;
  private javax.swing.JLabel lblCount;
  private javax.swing.JLabel lblTag;
  private javax.swing.JLabel lblTitle;
  private javax.swing.JPanel pnlMain;
  private javax.swing.JScrollPane scpResults;
  private javax.swing.JTable tblResult;
  private javax.swing.JTextField txtTags;
  private javax.swing.JTextField txtTitle;
  // End of variables declaration//GEN-END:variables
  JPopupMenu mnuResults;
  JMenuItem mniEdit, mniDelete;

  private String searchInTags(String keyword) {
    PasswordTag[] tags = PasswordTag.getAllTags();

    for (int i = 0; i < tags.length; i++) {
      PasswordTag passwordTag = tags[i];
      String tagTitle = passwordTag.getTitle();

      if (tagTitle.indexOf(keyword.toLowerCase()) == 0) {
        return tagTitle;
      }
    }
    return "";
  }

  private void doSearch() {
    DefaultTableModel model = (DefaultTableModel) tblResult.getModel();
    int numrows = model.getRowCount();
    for (int i = numrows - 1; i >= 0; i--) {
      model.removeRow(i);
    }

    Domain domain = Domain.getInstance();
    Connection con = null;
    try {
      con = domain.getDBConnection();
      Statement st = con.createStatement();
      String sql = "SELECT DISTINCT pe.* FROM PASSWORD_ENTRY pe LEFT OUTER JOIN "
              + "PASSWORD_ENTRY_PASSWORD_TAG pept ON (pe.ID = pept.PASSWORD_ENTRY_ID) LEFT OUTER JOIN "
              + "PASSWORD_TAG pt ON (pt.ID = pept.PASSWORD_TAG_ID) "
              + "WHERE 1 = 1";
      sql += txtTitle.getText().trim().length() > 0 ? " AND UPPER (pe.TITLE) LIKE UPPER('%" + txtTitle.getText().trim() + "%')" : "";
      sql += makeWhereClauseOfTags();

      int count = 0;
      ResultSet rs = st.executeQuery(sql);
      while (rs.next()) {
        count++;
        ((DefaultTableModel) tblResult.getModel()).addRow(
                new Object[]{rs.getString("title"), rs.getString("username"), rs.getString("url"), rs.getInt("id")});
      }

      lblCount.setText(countCaption + ": " + count);

    } catch (SQLException ex) {
      Logger.log(ex.getMessage());
    } finally {
      if (con != null) {
        try {
          con.close();
        } catch (SQLException ex) {
          Logger.log(ex.getMessage());
        }
      }
    }
  }

  private String makeWhereClauseOfTags() {
    String strTags = txtTags.getText().trim();
    if (strTags.length() <= 0) {
      return "";
    }

    String result = "";
    StringTokenizer tokenTags = new StringTokenizer(strTags, ",");
    while (tokenTags.hasMoreTokens()) {
      String tag = tokenTags.nextToken().trim().toLowerCase();
      result = String.format(" AND pt.TITLE LIKE ('%s')", tag);
    }
    return result;
  }

  private void myInitComponent() {
    //DefaultTableModel model = (DefaultTableModel) tblResult.getModel();
    TableResultColumnModel columnModel = new TableResultColumnModel();
    tblResult.setColumnModel(columnModel);
    tblResult.createDefaultColumnsFromModel();

    TableColumn column = columnModel.getColumnByModelIndex(3);
    columnModel.setColumnVisible(column, false);

    //<editor-fold defaultstate="collapsed" desc="Popup Menu">
    mnuResults = new JPopupMenu();

    URL url = ResourceLoader.class.getResource("edit.png");
    mniEdit = new JMenuItem("Edit", new ImageIcon(url));

    url = ResourceLoader.class.getResource("delete.png");
    mniDelete = new JMenuItem("Delete", new ImageIcon(url));

    mnuResults.add(mniEdit);
    mnuResults.add(mniDelete);

    ActionListener listenerForMenuItems = (new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        if (e.getSource() == mniEdit) {
          showPassword();
        } else {
          deletePassword();
        }
      }
    });

    mniEdit.addActionListener(listenerForMenuItems);
    mniDelete.addActionListener(listenerForMenuItems);
    //</editor-fold>

    txtTitle.requestFocus();
    MainFrame mainFrame = (MainFrame) getParent();
    if (mainFrame.getCurrentLanguage() != null) {
      changeLanguage(mainFrame.getCurrentLanguage());
    }
  }

  private void closeDialog() {
    setVisible(false);
    dispose();
  }

  private void showPassword() {
    int row = tblResult.getSelectedRow();
    row = tblResult.convertRowIndexToModel(row);

    if (row >= 0) {
      DefaultTableModel model = (DefaultTableModel) tblResult.getModel();
      Integer id = (Integer) model.getValueAt(row, 3);

      PasswordEntry passwordEntry = new PasswordEntry(id);
      passwordEntry.load();
      MainFrame owner = (MainFrame) getOwner();
      owner.setPasswordEntry(passwordEntry);
      owner.displayPasswordEntry();

      closeDialog();
    }
  }

  private void deletePassword() {
    int row = tblResult.getSelectedRow();
    row = tblResult.convertRowIndexToModel(row);

    if (row >= 0) {
      DefaultTableModel model = (DefaultTableModel) tblResult.getModel();
      Integer id = (Integer) model.getValueAt(row, 3);

      PasswordEntry passwordEntry = new PasswordEntry(id);
      passwordEntry.load();

      int answer = JOptionPane.showConfirmDialog(this, "Do you want to delete this password?", "Delete",
              JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

      if (answer == JOptionPane.YES_OPTION) {
        if (passwordEntry.delete()) {
          model.removeRow(row);
        } else {
          JOptionPane.showMessageDialog(this, "Error occured!\n Take a look at log file for more details.", "Error", JOptionPane.ERROR_MESSAGE);
        }
      }
    }
  }

  private void changeLanguage(Properties currentLanguage) {
    try {
      setDirection(currentLanguage.getProperty("direction"));
      setTitle(currentLanguage.getProperty("Search"));
      lblTitle.setText(currentLanguage.getProperty("Title") + ":");
      lblTag.setText(currentLanguage.getProperty("Tag") + ":");
      btnSearch.setText(currentLanguage.getProperty("Search"));
      countCaption = currentLanguage.getProperty("Count");
            
      TableColumnModel columnModel = tblResult.getTableHeader().getColumnModel();
      columnModel.getColumn(0).setHeaderValue(currentLanguage.getProperty("Title"));
      columnModel.getColumn(1).setHeaderValue(currentLanguage.getProperty("Username"));
      columnModel.getColumn(2).setHeaderValue(currentLanguage.getProperty("URL"));
      
      refresh();
    } catch (Exception ex) {
      JOptionPane.showMessageDialog(this, "Error occured in changing language!", "Error", JOptionPane.ERROR_MESSAGE);
    }
  }
  
  private void setDirection(String direction) {
    if (direction.equals("rtl")) {
      setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
      pnlMain.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
      
      for (int i = 0; i < pnlMain.getComponents().length; i++) {
        Component component = pnlMain.getComponents()[i];
        component.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
      }
    } else if (direction.equals("ltr")) {
      setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
      pnlMain.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
      
      for (int i = 0; i < pnlMain.getComponents().length; i++) {
        Component component = pnlMain.getComponents()[i];
        component.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
      }
    }
  }

  private void refresh() {
    pnlMain.setVisible(false);
    pnlMain.setVisible(true);
  }
}
